package util.hashing;

import java.util.Comparator;

import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeSet;
import java.util.Map.Entry;

public class Sorting {

	/**
	 * @param args
	 */

	public static Iterator<Entry<String, Float>> getTopN_Tuples(
			Hashtable<String, Float> hash, boolean ascending, int n) {

		Iterator<Entry<String, Float>> iter = sortHashNumericValues(hash,
				ascending);

		LinkedList<Entry<String, Float>> list = new LinkedList<Entry<String, Float>>();
		int i = 0;
		while (iter.hasNext() && i < n) {

			list.add(iter.next());

			i++;
		}

		return list.iterator();
	}

	public static HashSet<String> hashToSet(Hashtable<String, Object> hash) {

		HashSet<String> set = new HashSet<String>();

		Enumeration<String> keys = hash.keys();

		while (keys.hasMoreElements()) {

			set.add(keys.nextElement());

		}

		return set;

	}

	public static HashSet<String> getTopN(Hashtable<String, Float> hash,
			boolean ascending, int max, float threshold, int minimum) {

		Iterator<String> iter = getTopN_Threshold(hash, ascending, max,
				threshold, minimum);

		HashSet<String> set = new HashSet<String>();

		while (iter.hasNext()) {

			set.add(iter.next());
		}
		return set;
	}

	public static Iterator<String> getTopN_Threshold(
			Hashtable<String, Float> hash, boolean ascending, int max,
			float threshold, int minimum) {

		Iterator<Entry<String, Float>> iter = sortHashNumericValues(hash,
				ascending);

		LinkedList<String> list = new LinkedList<String>();
		int i = 0;

		boolean contin = true;
		while (iter.hasNext() && contin) {

			if (i > max && i > minimum) {
				contin = false;

			}

			Entry<String, Float> item = iter.next();
			if (item.getValue() < threshold && i > minimum) {

				contin = false;
			}
			if (contin == true)
				list.add(item.getKey());

			i++;
		}

		return list.iterator();
	}

	public static Iterator<String> getTopN(Hashtable<String, Float> hash,
			boolean ascending, int n) {

		Iterator<Entry<String, Float>> iter = sortHashNumericValues(hash,
				ascending);

		LinkedList<String> list = new LinkedList<String>();
		int i = 0;
		while (iter.hasNext() && i < n) {

			list.add(iter.next().getKey());

			i++;
		}

		return list.iterator();
	}

	public static Iterator<String> filterByThreshold(
			Hashtable<String, Float> hash, boolean below, float threshold) {

		boolean ascending = false;

		if (below)
			ascending = true;

		Iterator<Entry<String, Float>> iter = sortHashNumericValues(hash,
				ascending);

		LinkedList<String> list = new LinkedList<String>();

		while (iter.hasNext()) {

			Entry<String, Float> entry = iter.next();

			if (below) {

				if (entry.getValue() <= threshold) {
					list.add(entry.getKey());

				} else
					return list.iterator();

			} else {

				if (entry.getValue() >= threshold)
					list.add(entry.getKey());
				else
					return list.iterator();

			}

		}

		return list.iterator();
	}

	public static Iterator<Entry<String, Float>> filterByThreshold_Tuples(
			Hashtable<String, Float> hash, boolean below, float threshold) {

		boolean ascending = false;

		if (below)
			ascending = true;

		Iterator<Entry<String, Float>> iter = sortHashNumericValues(hash,
				ascending);

		LinkedList<Entry<String, Float>> list = new LinkedList<Entry<String, Float>>();

		while (iter.hasNext()) {

			Entry<String, Float> entry = iter.next();

			if (below) {

				if (entry.getValue() <= threshold) {
					list.add(entry);

				} else
					return list.iterator();

			} else {

				if (entry.getValue() >= threshold)
					list.add(entry);
				else
					return list.iterator();

			}

		}

		return list.iterator();
	}

	public static Iterator<Entry<String, Float>> sortHashNumericValues(
			Hashtable<String, Float> hash, boolean ascending) {

		// int count = 0; ==> just get the size from the map!

		TreeSet tree = new TreeSet(new MyComparator(ascending));

		tree.addAll(hash.entrySet());

		Iterator<Entry<String, Float>> iter = tree.iterator();

		return iter;

	}
	
	public static Iterator<Entry<String, Integer>> sortHashNumericValuesInteger(
			Hashtable<String, Integer> hash, boolean ascending) {

		// int count = 0; ==> just get the size from the map!

		TreeSet tree = new TreeSet(new MyComparator3(ascending));

		tree.addAll(hash.entrySet());

		Iterator<Entry<String, Integer>> iter = tree.iterator();

		return iter;

	}
	
	
	public static Iterator<Entry<String,Double>> sortHashNumericValuesDouble(
			Hashtable<String, Double> hash, boolean ascending) {

		// int count = 0; ==> just get the size from the map!

		TreeSet tree = new TreeSet(new MyComparator2(ascending));

		tree.addAll(hash.entrySet());

		Iterator<Entry<String, Double>> iter = tree.iterator();

		return iter;

	}

	

	public static Iterator<Entry<String, Float>> sortHashbyValues(
			Hashtable<String, Object> hash, boolean ascending) {

		// int count = 0; ==> just get the size from the map!

		TreeSet tree = new TreeSet(new GeneralComparator(ascending));

		tree.addAll(hash.entrySet());

		Iterator<Entry<String, Float>> iter = tree.iterator();

		return iter;

	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Hashtable<String, Float> hash = new Hashtable<String, Float>();

		hash.put("a", new Float(1.1));
		hash.put("b", new Float(2.1));
		hash.put("c", new Float(3.0));

		Iterator iter = Sorting.filterByThreshold(hash, false, 2.0f);

		while (iter.hasNext()) {

			Map.Entry<String, Float> a = (Entry<String, Float>) iter.next();

			System.out.println(a.getKey() + ":" + a.getValue());
		}

	}

	static class GeneralComparator implements Comparator {

		boolean ascending = false;

		public GeneralComparator(boolean ascending) {

			this.ascending = ascending;

		}

		public int compare(Map.Entry<String, Object> e1,
				Map.Entry<String, Object> e2) {

			int result = 0;

			Float value1 = Float.valueOf((e1.getValue()).toString());
			Float value2 =  Float.valueOf((e2.getValue()).toString());

			if (value1.compareTo(value2) == 0) {

				String word1 = (String) e1.getKey();
				String word2 = (String) e2.getKey();

				// Sort String in an alphabetical order

				result = word1.compareToIgnoreCase(word2);

			} else {
				// Sort values in a descending order
				if (!ascending)
					result = value2.compareTo(value1);
				else {

					result = value1.compareTo(value2);
				}

			}

			return result;
		}

		@Override
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub

			Map.Entry<String, Float> e1 = (Entry<String, Float>) arg0;

			Map.Entry<String, Float> e2 = (Entry<String, Float>) arg1;

			return compare(e1, e2);

		}

	}

	
	static class MyComparator2 implements Comparator {

		boolean ascending = false;

		public MyComparator2(boolean ascending) {

			this.ascending = ascending;

		}

		public int compare(Map.Entry<String,Double> e1,
				Map.Entry<String, Double> e2) {

			int result = 0;

			Double value1 = (Double) e1.getValue();
			Double value2 = (Double) e2.getValue();

			if (value1.compareTo(value2) == 0) {

				String word1 = (String) e1.getKey();
				String word2 = (String) e2.getKey();

				// Sort String in an alphabetical order

				result = word1.compareToIgnoreCase(word2);
				
			} else {
				// Sort values in a descending order
				if (!ascending)
					result = value2.compareTo(value1);
				else {

					result = value1.compareTo(value2);
				}

			}

			return result;
		}

		@Override
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub

			Map.Entry<String, Double> e1 = (Entry<String, Double>) arg0;

			Map.Entry<String, Double> e2 = (Entry<String, Double>) arg1;

			return compare(e1, e2);

		}

	}
	
	
	
	static class MyComparator3 implements Comparator {

		boolean ascending = false;

		public MyComparator3(boolean ascending) {

			this.ascending = ascending;

		}

		public int compare(Map.Entry<String,Integer> e1,
				Map.Entry<String, Integer> e2) {

			int result = 0;

			Integer value1 = (Integer) e1.getValue();
			Integer value2 = (Integer) e2.getValue();

			if (value1.compareTo(value2) == 0) {

				String word1 = (String) e1.getKey();
				String word2 = (String) e2.getKey();

				// Sort String in an alphabetical order

				result = word1.compareToIgnoreCase(word2);
				
			} else {
				// Sort values in a descending order
				if (!ascending)
					result = value2.compareTo(value1);
				else {

					result = value1.compareTo(value2);
				}

			}

			return result;
		}

		@Override
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub

			Map.Entry<String, Integer> e1 = (Entry<String, Integer>) arg0;

			Map.Entry<String, Integer> e2 = (Entry<String, Integer>) arg1;

			return compare(e1, e2);

		}

	}
	static class MyComparator implements Comparator {

		boolean ascending = false;

		public MyComparator(boolean ascending) {

			this.ascending = ascending;

		}

		public int compare(Map.Entry<String, Float> e1,
				Map.Entry<String, Float> e2) {

			int result = 0;

			Float value1 = (Float) e1.getValue();
			Float value2 = (Float) e2.getValue();

			if (value1.compareTo(value2) == 0) {

				String word1 = (String) e1.getKey();
				String word2 = (String) e2.getKey();

				// Sort String in an alphabetical order

				result = word1.compareToIgnoreCase(word2);
				
			} else {
				// Sort values in a descending order
				if (!ascending)
					result = value2.compareTo(value1);
				else {

					result = value1.compareTo(value2);
				}

			}

			return result;
		}

		@Override
		public int compare(Object arg0, Object arg1) {
			// TODO Auto-generated method stub

			Map.Entry<String, Float> e1 = (Entry<String, Float>) arg0;

			Map.Entry<String, Float> e2 = (Entry<String, Float>) arg1;

			return compare(e1, e2);

		}

	}

}


